package net.xo68.destiny.starter.worker.config;

import lombok.extern.slf4j.Slf4j;
import net.xo68.destiny.contract.common.SystemConstants;
import net.xo68.destiny.contract.domain.RespondResult;
import net.xo68.destiny.contract.domain.StringRespondResult;
import net.xo68.destiny.contract.domain.node.NodeRegistry;
import net.xo68.destiny.contract.enums.NodeTypeEnum;
import net.xo68.destiny.core.discovery.NodeDiscoveryRunner;
import net.xo68.destiny.core.discovery.NodeMapStore;
import net.xo68.destiny.core.rpc.RpcClient;
import net.xo68.destiny.core.util.IpUtil;
import net.xo68.destiny.core.util.OSUtils;
import net.xo68.destiny.core.util.TimeUtils;
import net.xo68.destiny.starter.common.SchedulerCommonProperties;
import net.xo68.destiny.starter.worker.SchedulerWorkerProperties;
import net.xo68.destiny.starter.worker.domain.RespondResultNodeRegistryList;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 工作节点注册发现定时处理实现
 * @author wuxie
 * @version 2020-11-19
 */
@Slf4j
@Component
public class NodeDiscoveryRunnerImpl  implements NodeDiscoveryRunner {

    private static final String SERVER_PORT="server.port";

    @Autowired
    private Environment environment;
    @Autowired
    private SchedulerCommonProperties schedulerCommonProperties;
    @Autowired
    private SchedulerWorkerProperties schedulerWorkerProperties;
    @Autowired
    private RpcClient rpcClient;

    @Override
    public void startLoad(NodeMapStore nodeMapStore) {
        //log.info("工作节点注册发现 启动加载...");
        if(StringUtils.isEmpty(schedulerWorkerProperties.getManager())){
            log.error("未配置管理节点主机，配置key: destiny.worker.manager,如: 12.11.18.55:8080,12.11.18.56:8080,12.11.18.57:8080");
            return;
        }
        String[] hosts=schedulerWorkerProperties.getManager().split(",");
        final List<NodeRegistry> nodeRegistryList=manageNodeFactory(hosts);
        nodeMapStore.merge(nodeRegistryList);

        //registrySelf(nodeMapStore);
    }

    @Override
    public void execute(NodeMapStore nodeMapStore) {
        //log.info("工作节点注册发现 定时处理...");
        try{
            String manageHost=getManageHost(nodeMapStore);
            if(StringUtils.isBlank(manageHost)){
                log.error("取注册信息失败,原因: {}","没有任何管理节点");
                return;
            }
            //log.debug("node discovery: {}",schedulerWorkerProperties.getWorkGroup());
            RespondResult<List<NodeRegistry>> result = rpcClient.tryGet(nodeMapStore.getManageHosts(),manageHost, "/api/discovery", RespondResultNodeRegistryList.class, schedulerWorkerProperties.getWorkGroup());
            if(result.isFail()){
                log.error("取注册信息失败");
            }else {
                if(result.getBody().size()>0) {
                    nodeMapStore.merge(result.getBody());
                }
            }
        }catch (Exception e){
            log.error(e.getMessage(),e);
        }
        registrySelf(nodeMapStore);
    }

    @Override
    public void downline(NodeMapStore nodeMapStore) {
        try{
            NodeRegistry nodeRegistry=new NodeRegistry();
            nodeRegistry.setNodeType(NodeTypeEnum.WORKER);
            nodeRegistry.setWorkGroup(schedulerWorkerProperties.getWorkGroup());
            String host= IpUtil.getIpPort(schedulerCommonProperties.getNodeRealIp(),environment.getProperty(SERVER_PORT));
            nodeRegistry.setNodeHost(host);
            nodeRegistry.setCpuUsage(OSUtils.cpuUsage());
            nodeRegistry.setMemoryUsage(OSUtils.memoryUsage());
            nodeRegistry.setLoadAverage(OSUtils.loadAverage());
            nodeRegistry.setLastTime(TimeUtils.nowDate());

            log.debug("worker downline: {}",nodeRegistry);
            String manageHost=getManageHost(nodeMapStore);
            if(StringUtils.isBlank(manageHost)){
                log.error("上报心跳信息失败,原因: {}","没有任何管理节点");
                return;
            }
            StringRespondResult result = rpcClient.postJson(manageHost, "/api/downline", StringRespondResult.class, nodeRegistry);
            if(result.isFail()){
                log.error("上报心跳信息失败");
            }
        }catch (Exception e){
            log.error(e.getMessage(),e);
        }
    }

    private List<NodeRegistry> manageNodeFactory(String[] hosts){

        final List<NodeRegistry> nodeRegistryList= new ArrayList<>();
        if(hosts!=null && hosts.length>0){
            Arrays.stream(hosts).forEach(host->{
                NodeRegistry nodeRegistry=new NodeRegistry();
                nodeRegistry.setNodeType(NodeTypeEnum.MANAGER);
                nodeRegistry.setWorkGroup(SystemConstants.STRING_EMPTY);
                 nodeRegistry.setNodeHost(host);
                nodeRegistry.setCpuUsage(0L);
                nodeRegistry.setMemoryUsage(0L);
                nodeRegistry.setLoadAverage(0L);
                nodeRegistry.setLastTime(TimeUtils.nowDate());
                nodeRegistryList.add(nodeRegistry);
            });
        }
        return nodeRegistryList;
    }

    private String getManageHost(final NodeMapStore nodeMapStore){
        List<String> manageNodes = nodeMapStore.getManageHosts();
        if(manageNodes==null || manageNodes.isEmpty()){
            return SystemConstants.STRING_EMPTY;
        }
        String manageHost=SystemConstants.STRING_EMPTY;
        if(manageNodes.size()<2){
            manageHost=manageNodes.get(0);
        }else {
            manageHost=manageNodes.get(RandomUtils.nextInt(0,manageNodes.size()));

        }
        //log.info(">>>>  manageHost: {}", manageHost);
        return manageHost;
    }

    /**
     * 注册自己
     */
    private void registrySelf(final NodeMapStore nodeMapStore){
        //上报本管理端节点
        try{
            NodeRegistry nodeRegistry=new NodeRegistry();
            nodeRegistry.setNodeType(NodeTypeEnum.WORKER);
            nodeRegistry.setWorkGroup(schedulerWorkerProperties.getWorkGroup());
            String host= IpUtil.getIpPort(schedulerCommonProperties.getNodeRealIp(),environment.getProperty(SERVER_PORT));
            nodeRegistry.setNodeHost(host);
            nodeRegistry.setCpuUsage(OSUtils.cpuUsage());
            nodeRegistry.setMemoryUsage(OSUtils.memoryUsage());
            nodeRegistry.setLoadAverage(OSUtils.loadAverage());
            nodeRegistry.setLastTime(TimeUtils.nowDate());


            nodeMapStore.addWorkNode(nodeRegistry);
            //log.debug("worker heartbeat: {}",nodeRegistry);

            String manageHost=getManageHost(nodeMapStore);
            if(StringUtils.isBlank(manageHost)){
                log.error("上报心跳信息失败,原因: {}","没有任何管理节点");
                return;
            }

            StringRespondResult result = rpcClient.tryPostJson(nodeMapStore.getManageHosts(),manageHost, "/api/heartbeat", StringRespondResult.class, nodeRegistry);
            if(result==null || result.isFail()){
                log.error("上报心跳信息失败");
            }
        }catch (Exception e){
            log.error(e.getMessage(),e);
        }

    }
}
